package com.example.exceldemo.service.impl;

import com.alibaba.excel.EasyExcel;
import com.example.exceldemo.config.AppConfig;
import com.example.exceldemo.config.DocConfig;
import com.example.exceldemo.constants.DocConstants;
import com.example.exceldemo.exception.BizException;
import com.example.exceldemo.listener.ReqDataListener;
import com.example.exceldemo.model.DemoContext;
import com.example.exceldemo.model.ReqInfoDTO;
import com.example.exceldemo.service.DocGeneratorService;
import com.example.exceldemo.service.DocTaskService;
import com.example.exceldemo.service.TaskService;
import com.example.exceldemo.util.ConfigUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.UUID;

/**
 * 文档生成服务实现类
 * 
 * @author system
 */
@Slf4j
@Service
public class DocGeneratorServiceImpl implements DocGeneratorService {

    /**
     * 上传目录
     */
    private final String uploadDir;

    /**
     * 输出目录
     */
    private final String outputDir;

    /**
     * 配置文件路径
     */
    private final String configFilePath;

    /**
     * 文档配置
     */
    private final DocConfig docConfig;

    /**
     * LiteFlow执行器
     */
    private final FlowExecutor flowExecutor;

    /**
     * 任务服务
     */
    private final TaskService taskService;
    
    /**
     * 文档任务服务
     */
    private final DocTaskService docTaskService;

    /**
     * 构造方法注入
     * 
     * @param appConfig 应用配置
     * @param docConfig 文档配置
     * @param flowExecutor LiteFlow执行器
     * @param taskService 任务服务
     * @param docTaskService 文档任务服务
     */
    public DocGeneratorServiceImpl(AppConfig appConfig, DocConfig docConfig, FlowExecutor flowExecutor, 
            TaskService taskService, DocTaskService docTaskService) {
        this.uploadDir = appConfig.getUpload().getDir();
        this.outputDir = appConfig.getOutput().getDir();
        this.configFilePath = appConfig.getConfig().getFile();
        this.docConfig = docConfig;
        this.flowExecutor = flowExecutor;
        this.taskService = taskService;
        this.docTaskService = docTaskService;
        
        log.info("初始化DocGeneratorService，上传目录: {}, 输出目录: {}, 配置文件: {}", 
                uploadDir, outputDir, configFilePath);
    }

    @Override
    public List<ReqInfoDTO> processExcel(String filePath) {
        // 参数校验
        if (filePath == null || filePath.trim().isEmpty()) {
            throw BizException.paramError("文件路径不能为空");
        }
        
        List<ReqInfoDTO> reqInfoDTOS;
        
        try {
            log.info("开始处理Excel文件: {}", filePath);
            
            // 使用try-with-resources确保资源被正确关闭
            try (InputStream inputStream = new FileInputStream(filePath)) {
                ReqDataListener listener = new ReqDataListener();
                reqInfoDTOS = EasyExcel.read(inputStream)
                        .head(ReqInfoDTO.class)
                        .registerReadListener(listener)
                        .sheet()
                        .doReadSync();
            }
            
            if (CollectionUtils.isEmpty(reqInfoDTOS)) {
                log.warn("Excel文件中未找到有效的需求数据");
                throw BizException.fileParseError("Excel文件中未找到有效的需求数据");
            }
            
            log.info("Excel处理完成，共读取{}条记录", reqInfoDTOS.size());
            
            return reqInfoDTOS;
        } catch (BizException e) {
            throw e;
        } catch (Exception e) {
            log.error("处理Excel文件失败: {}", e.getMessage(), e);
            throw BizException.fileParseError("处理Excel文件失败: " + e.getMessage());
        }
    }

    @Override
    public String generateDocuments(String filePath, List<String> selectedReqs) {
        try {
            // 参数校验
            if (filePath == null || filePath.trim().isEmpty()) {
                throw BizException.paramError("文件路径不能为空");
            }
            
            List<ReqInfoDTO> allReqs = processExcel(filePath);
            
            // 委托给新方法处理
            return generateDocumentsFromList(allReqs, selectedReqs);
        } catch (BizException e) {
            throw e;
        } catch (Exception e) {
            log.error("生成文档失败: {}", e.getMessage(), e);
            throw BizException.docGenerateError("生成文档失败: " + e.getMessage());
        }
    }

    @Override
    public String generateDocumentsAsync(String filePath, List<String> selectedReqs, String metadata) {
        log.info("创建异步文档生成任务（基于文件路径），文件路径: {}, 选定需求: {}", filePath, selectedReqs);
        
        // 参数校验
        if (filePath == null || filePath.trim().isEmpty()) {
            throw BizException.paramError("文件路径不能为空");
        }
        
        // 读取Excel数据
        List<ReqInfoDTO> allReqs = processExcel(filePath);
        
        // 委托给新方法处理
        return generateDocumentsAsync(allReqs, selectedReqs, metadata);
    }

    @Override
    public String generateDocumentsAsync(List<ReqInfoDTO> reqInfoList, List<String> selectedReqs, String metadata) {
        log.info("创建异步文档生成任务，需求列表长度: {}, 选定需求: {}", reqInfoList.size(), selectedReqs);
        
        // 创建数据库持久化任务
        String taskId;
        try {
            // 使用docTaskService创建持久化到数据库的任务
            taskId = docTaskService.createTask(null, selectedReqs);
            log.info("任务已创建并保存到数据库: {}", taskId);
        } catch (Exception e) {
            log.error("创建数据库任务失败", e);
            // 如果数据库任务创建失败，回退到内存任务
            taskId = taskService.createTask("DOC_GENERATE", metadata).getTaskId();
            log.warn("回退到内存任务: {}", taskId);
        }
        
        // 异步执行文档生成
        final String finalTaskId = taskId;
        CompletableFuture.runAsync(() -> {
            try {
                // 更新进度为30%（开始处理）
                docTaskService.updateTaskStatus(finalTaskId, "PROCESSING", 30, null, null);
                
                // 如果提供了选定的需求编号列表，则只处理这些需求
                List<ReqInfoDTO> reqsToProcess;
                if (!CollectionUtils.isEmpty(selectedReqs)) {
                    reqsToProcess = reqInfoList.stream()
                            .filter(req -> selectedReqs.contains(req.getReqNo()))
                            .collect(Collectors.toList());
                    log.info("从{}个需求中选择了{}个需求进行处理", reqInfoList.size(), reqsToProcess.size());
                } else {
                    reqsToProcess = reqInfoList;
                    log.info("处理所有{}个需求", reqInfoList.size());
                }
                
                if (CollectionUtils.isEmpty(reqsToProcess)) {
                    docTaskService.updateTaskStatus(finalTaskId, "FAILED", 0, null, "没有找到需要处理的需求");
                    return;
                }
                
                // 更新进度为40%（选择需要处理的需求完成）
                docTaskService.updateTaskStatus(finalTaskId, "PROCESSING", 40, null, null);
                
                // 创建输出目录
                String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern(DocConstants.DatePattern.DATE));
                String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern(DocConstants.DatePattern.TIME));
                String outputDirPath = Paths.get(outputDir, dateStr + "_" + timestamp).toString();
                
                createOutputDirectory(outputDirPath);
                
                // 更新进度为50%（创建输出目录完成）
                docTaskService.updateTaskStatus(finalTaskId, "PROCESSING", 50, null, null);
                
                // 获取当前设置
                Map<String, String> settings = getSettings();
                log.info("使用配置参数: {}", settings);
                
                // 设置模板目录
                DemoContext context = new DemoContext();
                context.setReqInfoDTOS(reqsToProcess);
                context.setOutputDirPath(outputDirPath);
                context.setSettings(settings);
                context.setTaskId(finalTaskId);
                context.setTemplateDir(docConfig.getTemplate().getDir());
                
                // 更新进度为60%（配置设置完成）
                docTaskService.updateTaskStatus(finalTaskId, "PROCESSING", 60, null, null);
                String chainId = "";
                if ("GS".equals(reqsToProcess.get(0).getProvCode())) {
                    chainId = "chainGS";
                }else if ("QH".equals(reqsToProcess.get(0).getProvCode())) {
                    chainId = "chainQH";
                }else{
                    throw new RuntimeException("未知的省份编码");
                }
                // 调用文档生成流程
                LiteflowResponse response = flowExecutor.execute2Resp(chainId, null, context);
                
                // 更新进度为90%（文档生成流程执行完成）
                docTaskService.updateTaskStatus(finalTaskId, "PROCESSING", 90, null, null);
                
                if (!response.isSuccess()) {
                    String errorMsg = "文档生成流程执行失败: " + response.getMessage();
                    log.error(errorMsg);
                    docTaskService.updateTaskStatus(finalTaskId, "FAILED", 0, null, errorMsg);
                    return;
                }
                
                // 更新任务状态为完成
                docTaskService.updateTaskStatus(finalTaskId, "COMPLETED", 100, outputDirPath, null);
                log.info("异步文档生成任务完成，任务ID: {}, 输出目录: {}", finalTaskId, outputDirPath);
            } catch (Exception e) {
                log.error("异步文档生成任务执行出错", e);
                docTaskService.updateTaskStatus(finalTaskId, "FAILED", 0, null, "执行异常: " + e.getMessage());
            }
        });
        
        return taskId;
    }

    @Override
    public String generateDocumentsFromList(List<ReqInfoDTO> reqInfoList, List<String> selectedReqs) {
        try {
            // 参数校验
            if (CollectionUtils.isEmpty(reqInfoList)) {
                throw BizException.paramError("需求信息列表不能为空");
            }
            
            // 如果提供了选定的需求编号列表，则只处理这些需求
            List<ReqInfoDTO> reqsToProcess;
            if (!CollectionUtils.isEmpty(selectedReqs)) {
                reqsToProcess = reqInfoList.stream()
                        .filter(req -> selectedReqs.contains(req.getReqNo()))
                        .collect(Collectors.toList());
                log.info("从{}个需求中选择了{}个需求进行处理", reqInfoList.size(), reqsToProcess.size());
            } else {
                reqsToProcess = reqInfoList;
                log.info("处理所有{}个需求", reqInfoList.size());
            }
            
            if (CollectionUtils.isEmpty(reqsToProcess)) {
                log.warn("没有找到需要处理的需求");
                throw BizException.docGenerateError("没有找到需要处理的需求");
            }
            
            // 创建输出目录
            String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern(DocConstants.DatePattern.DATE));
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern(DocConstants.DatePattern.TIME));
            String outputDirPath = Paths.get(outputDir, dateStr + "_" + timestamp).toString();
            
            createOutputDirectory(outputDirPath);
            
            // 获取当前设置
            Map<String, String> settings = getSettings();
            log.info("使用配置参数: {}", settings);
            
            // 设置模板目录
            DemoContext context = new DemoContext();
            context.setReqInfoDTOS(reqsToProcess);
            context.setOutputDirPath(outputDirPath);
            context.setSettings(settings);
            context.setTemplateDir(docConfig.getTemplate().getDir());
            
            // 调用文档生成流程
            LiteflowResponse response = flowExecutor.execute2Resp("chain1", null, context);
            if (!response.isSuccess()) {
                String errorMsg = "文档生成流程执行失败: " + response.getMessage();
                log.error(errorMsg);
                throw BizException.docGenerateError(errorMsg);
            }
            
            log.info("文档生成完成，输出目录: {}", outputDirPath);
            return outputDirPath;
        } catch (BizException e) {
            throw e;
        } catch (Exception e) {
            log.error("生成文档失败: {}", e.getMessage(), e);
            throw BizException.docGenerateError("生成文档失败: " + e.getMessage());
        }
    }

    @Override
    public List<ReqInfoDTO> processExcelFromMemory(MultipartFile file) {
        // 参数校验
        if (file == null || file.isEmpty()) {
            throw BizException.paramError("Excel文件不能为空");
        }
        
        List<ReqInfoDTO> reqInfoDTOS;
        
        try {
            log.info("开始处理上传的Excel文件: {}", file.getOriginalFilename());
            
            // 直接从输入流读取Excel数据
            try (InputStream inputStream = file.getInputStream()) {
                ReqDataListener listener = new ReqDataListener();
                reqInfoDTOS = EasyExcel.read(inputStream)
                        .head(ReqInfoDTO.class)
                        .registerReadListener(listener)
                        .sheet()
                        .doReadSync();
            }
            
            if (CollectionUtils.isEmpty(reqInfoDTOS)) {
                log.warn("Excel文件中未找到有效的需求数据");
                throw BizException.fileParseError("Excel文件中未找到有效的需求数据");
            }
            
            log.info("Excel处理完成，共读取{}条记录", reqInfoDTOS.size());
            
            return reqInfoDTOS;
        } catch (BizException e) {
            throw e;
        } catch (Exception e) {
            log.error("处理Excel文件失败: {}", e.getMessage(), e);
            throw BizException.fileParseError("处理Excel文件失败: " + e.getMessage());
        }
    }

    @Override
    public Map<String, String> getSettings() {
        try {
            Map<String, String> settings = ConfigUtil.readConfig(configFilePath);
            if (CollectionUtils.isEmpty(settings)) {
                log.info("配置文件为空或不存在，使用默认配置");
                return getDefaultSettings();
            }
            return settings;
        } catch (Exception e) {
            log.error("读取配置文件失败，使用默认配置", e);
            return getDefaultSettings();
        }
    }

    @Override
    public void saveSettings(Map<String, String> settings) {
        if (settings == null) {
            throw BizException.paramError("设置参数不能为空");
        }
        
        try {
            ConfigUtil.saveConfig(configFilePath, settings);
            log.info("配置已保存到: {}", configFilePath);
        } catch (Exception e) {
            log.error("保存配置文件失败", e);
            throw BizException.configError("保存配置失败: " + e.getMessage());
        }
    }

    /**
     * 创建输出目录
     * 
     * @param outputDirPath 输出目录路径
     */
    private void createOutputDirectory(String outputDirPath) {
        File outputDirFile = new File(outputDirPath);
        if (!outputDirFile.exists() && !outputDirFile.mkdirs()) {
            throw BizException.docGenerateError("创建输出目录失败: " + outputDirPath);
        }
        log.info("创建输出目录: {}", outputDirPath);
    }

    /**
     * 获取默认设置
     * 
     * @return 默认设置
     */
    private Map<String, String> getDefaultSettings() {
        Map<String, String> defaults = new HashMap<>(16);
        // 基本设置
        defaults.put(DocConstants.Settings.TEMPLATE_DIR, docConfig.getTemplate().getDir());
        defaults.put(DocConstants.Settings.OUTPUT_DIR, outputDir);
        defaults.put(DocConstants.Settings.AUDITOR, docConfig.getDefaultAuditor());
        defaults.put(DocConstants.Settings.AUTHOR, docConfig.getDefaultAuthor());
        defaults.put(DocConstants.Settings.DEPARTMENT, "技术部");
        defaults.put(DocConstants.Settings.ANALYSTS, "");
        
        // 文档设置
        defaults.put(DocConstants.Settings.VERSION, "1.0");
        defaults.put(DocConstants.Settings.COMPANY_NAME, "示例企业");
        defaults.put(DocConstants.Settings.CONFIDENTIALITY, "普通");
        
        // 需求参数
        defaults.put(DocConstants.Settings.IS_KEY, docConfig.getDefaultIsKey());
        defaults.put(DocConstants.Settings.URGENCY, docConfig.getDefaultUrgency());
        defaults.put(DocConstants.Settings.IS_URGENT, docConfig.getDefaultIsUrgent());
        defaults.put(DocConstants.Settings.DEFAULT_PRIORITY, "中");
        defaults.put(DocConstants.Settings.DEFAULT_COMPLEXITY, "一般");
        defaults.put(DocConstants.Settings.DEFAULT_RISK, "低风险");
        
        // 系统配置
        defaults.put(DocConstants.Settings.AUTO_BACKUP, "false");
        defaults.put(DocConstants.Settings.BACKUP_DIR, outputDir + File.separator + "backup");
        defaults.put(DocConstants.Settings.FILE_NAME_FORMAT, "{reqNo}_{reqName}");
        defaults.put(DocConstants.Settings.MAX_THREADS, "4");
        
        return defaults;
    }
} 